package com.mocai.merchant.core.service;

import com.mocai.merchant.core.domain.ColumnMapping;
import com.mocai.merchant.core.domain.Treeable;
import com.mocai.merchant.core.mapper.TreeableMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 可树状结构的
 */
@Service
public class TreeableService {

    @Autowired
    TreeableMapper treeableMapper;

    /**
     * 移动位置
     */
    private enum Position {
        TOP,    // 移动到第一行
        UP,     // 往上移动一行
        DOWN,   // 往下移动一行
        BOTTOM  // 移动到最后一行
    }

    /**
     * 交换同级结点的位置
     *
     * @param source     源
     * @param target     目标
     * @param table
     * @param idColumn
     * @param sortColumn
     * @param <T>
     */
    public <T extends Treeable> void exchange(T source, T target, String table, String idColumn, String sortColumn) {
        treeableMapper.exchange(source, target, table, idColumn, sortColumn);
    }

    /**
     * 交换同级结点的位置
     *
     * @param source
     * @param target
     * @param <T>
     */
    public <T extends Treeable> void exchange(T source, T target) {
        ColumnMapping cm = ColumnMapping.get(source.getClass());
        exchange(source, target, cm.getTable(), cm.getId(), cm.getSort());
    }

    /**
     * 把 from 移动到 to
     *
     * @param from
     * @param to
     * @param table
     * @param idColumn
     * @param sortColumn
     * @param parentColumn
     * @param <T>
     */
    public <T extends Treeable> void move(T from, T to, String table, String idColumn, String sortColumn, String parentColumn) {
        treeableMapper.move(from, to, table, idColumn, sortColumn, parentColumn);
    }

    /**
     * 把 from 移动到 to
     *
     * @param from
     * @param to
     * @param <T>
     */
    public <T extends Treeable> void move(T from, T to) {
        ColumnMapping cm = ColumnMapping.get(from.getClass());
        move(from, to, cm.getTable(), cm.getId(), cm.getSort(), cm.getParent());
    }

    /**
     * 把当前节点移到同级节点顶部
     *
     * @param model
     * @param table
     * @param idColumn
     * @param sortColumn
     * @param parentColumn
     * @param <T>
     */
    public <T extends Treeable> void top(T model, String table, String idColumn, String sortColumn, String parentColumn) {
        move(model, table, idColumn, sortColumn, parentColumn, Position.TOP);
    }

    /**
     * 把当前节点移到同级节点顶部
     *
     * @param model
     * @param <T>
     */
    public <T extends Treeable> void top(T model) {
        ColumnMapping cm = ColumnMapping.get(model.getClass());
        top(model, cm.getTable(), cm.getId(), cm.getSort(), cm.getParent());
    }

    /**
     * 把当前节点往上移动一个位置
     *
     * @param model
     * @param table
     * @param idColumn
     * @param sortColumn
     * @param parentColumn
     * @param <T>
     */
    public <T extends Treeable> void up(T model, String table, String idColumn, String sortColumn, String parentColumn) {
        move(model, table, idColumn, sortColumn, parentColumn, Position.UP);
    }

    /**
     * 把当前节点往上移动一个位置
     *
     * @param model
     * @param <T>
     */
    public <T extends Treeable> void up(T model) {
        ColumnMapping cm = ColumnMapping.get(model.getClass());
        up(model, cm.getTable(), cm.getId(), cm.getSort(), cm.getParent());
    }

    /**
     * 把当前节点往下移动一个位置
     *
     * @param model
     * @param table
     * @param idColumn
     * @param sortColumn
     * @param parentColumn
     * @param <T>
     */
    public <T extends Treeable> void down(T model, String table, String idColumn, String sortColumn, String parentColumn) {
        move(model, table, idColumn, sortColumn, parentColumn, Position.DOWN);
    }

    /**
     * 把当前节点往下移动一个位置
     *
     * @param model
     * @param <T>
     */
    public <T extends Treeable> void down(T model) {
        ColumnMapping cm = ColumnMapping.get(model.getClass());
        up(model, cm.getTable(), cm.getId(), cm.getSort(), cm.getParent());
    }

    /**
     * 把当前节点移动到同级节点底部
     *
     * @param model
     * @param table
     * @param idColumn
     * @param sortColumn
     * @param parentColumn
     * @param <T>
     */
    public <T extends Treeable> void bottom(T model, String table, String idColumn, String sortColumn, String parentColumn) {
        move(model, table, idColumn, sortColumn, parentColumn, Position.BOTTOM);
    }

    /**
     * 把当前节点移动到同级节点底部
     *
     * @param model
     * @param <T>
     */
    public <T extends Treeable> void bottom(T model) {
        ColumnMapping cm = ColumnMapping.get(model.getClass());
        bottom(model, cm.getTable(), cm.getId(), cm.getSort(), cm.getParent());
    }

    /**
     * 把 from 节点 移动 to 节点内部
     *
     * @param from
     * @param to
     * @param table
     * @param idColumn
     * @param pathColumn
     * @param sortColumn
     * @param parentColumn
     * @param <T>
     */
    public <T extends Treeable> void append(T from, T to, String table, String idColumn, String pathColumn, String sortColumn, String parentColumn) {
        // 同一个节点
        if (from.getId().equals(to.getId())) {
            return;
        }
        // 上级不能追加到下级
        List<String> pathItems = Arrays.asList(to.getPath().split("/"));
        if (pathItems.contains(from.getId().toString())) {
            return;
        }
        // 修改 from 的父节点为 to
        from.setParent(to.getId());
        // 将 from 放置到 to 的最后一个节点，找到to的最后一个子节点, 将from的排序值修改为to的最后一个节点的sort+1
        Map lastChildrenForTo = (Map) treeableMapper.selectLast(to, table, idColumn, sortColumn, parentColumn);
        Integer sort = (Integer) lastChildrenForTo.get(sortColumn);
        sort = (null == sort) ? 1 : sort++;
        from.setSort(sort);
        // 修改 from 的路径为 to 的路径加上ID
        String fromOldPath = from.getPath();
        from.setPath(to.getPath() + from.getId() + "/");
        from.setParent(to.getId());
        // 更新 from 子节点的 path
        treeableMapper.updateChildrenPath(from, fromOldPath, table, pathColumn, parentColumn);
        // 更新 from
        treeableMapper.update(from, table, idColumn, sortColumn, pathColumn, parentColumn);
    }

    /**
     * 把 from 节点 移动 to 节点内部
     *
     * @param from
     * @param to
     * @param <T>
     */
    public <T extends Treeable> void append(T from, T to) {
        ColumnMapping cm = ColumnMapping.get(from.getClass());
        append(from, to, cm.getTable(), cm.getId(), cm.getPath(), cm.getSort(), cm.getParent());
    }

    private <T extends Treeable> void move(T model, String table, String idColumn, String sortColumn, String parentColumn, Position position) {
        Map targetRow = null;
        switch (position) {
            case TOP:
                targetRow = (Map) treeableMapper.selectFirst(model, table, idColumn, sortColumn, parentColumn);
                break;
            case UP:
                targetRow = (Map) treeableMapper.selectPrevious(model, table, idColumn, sortColumn, parentColumn);
                break;
            case DOWN:
                targetRow = (Map) treeableMapper.selectNext(model, table, idColumn, sortColumn, parentColumn);
                break;
            case BOTTOM:
                targetRow = (Map) treeableMapper.selectLast(model, table, idColumn, sortColumn, parentColumn);
                break;
        }
        // 没有找到目标节点（两种可能：1.当前节点在顶部，向上移动 2.当前节点在底部，向下移动）
        if (null == targetRow) {
            return;
        }
        // 同一个节点
        if (targetRow.get(idColumn).equals(model.getId())) {
            return;
        }
        try {
            Treeable target = model.getClass().newInstance();
            target.setId(targetRow.get(idColumn));
            target.setSort((Integer) targetRow.get(sortColumn));
            target.setParent(targetRow.get(parentColumn));
            move(model, target, table, idColumn, sortColumn, parentColumn);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

}
